#include "Normalizador.h"
#include <locale>
#include <sstream>
#include <algorithm>
#include <functional>



char Normalizador::filtrarCaracter(wchar_t wc){
	// Convierte el caracter en numero
        int ci = (int) wc;

        // Los valores de los caracters permitidos
        int a = (int) 'a';
        int z = (int) 'z';
        int A = (int) 'A';
        int Z = (int) 'Z';

        // Los signos de puntuación permitidos
        int coma = (int) L',';
        int pipe = (int) L'|';
        int punto = (int) L'.';
        int espacio = (int) L' ';
        int comilla = (int) L'\'';
        int comillas = (int) L'"';
        int dos_puntos = (int) L':';
        int punto_y_coma = (int) L';';

        // Mas signos
        int pregunta_1 = (int) L'¿';
        int pregunta_2 = (int) L'?';
        int corchete_1 = (int) L'[';
        int corchete_2 = (int) L']';
        int exclamacion_1 = (int) L'¡';
        int exclamacion_2 = (int) L'!';


        // Compara que el caracter este dentro de los valores de las letras "normales"
        if ( (ci >= a && ci <= z) || (ci >= A && ci <=Z) ){

                return wc;

        } else if (ci == coma || ci == pipe || ci == punto || ci == comillas || ci == comilla
                        || ci == dos_puntos || ci == punto_y_coma || ci == espacio){
                // Es un signo valido
                return wc;

        } else if (ci == pregunta_1 || ci == pregunta_2 || ci == corchete_1 || ci == corchete_2
                        || ci == exclamacion_1 || ci == exclamacion_2){
                // Otro simbolo valido
                return wc;

        } else {
                // Tiene un simbolo diacrítico, hay que aplicarle una transformacion
                return transformarCaracter(wc);
        }
}


char Normalizador::transformarCaracter(wchar_t wc){
		int cint = (int) wc;
        switch (cint){
                        case (int) L'á':
                        case (int) L'ä':
                                return 'a';

                        case (int) L'Á':
                        case (int) L'Ä':
                                return 'A';

                        case (int) L'é':
                        case (int) L'ë':
                                return 'e';

                        case (int) L'É':
                        case (int) L'Ë':
                                return 'E';

                        case (int) L'í':
                        case (int) L'ï':
                        case (int) L'î':
                                return 'i';

                        case (int) L'Í':
                        case (int) L'Ï':
                        case (int) L'Î':
                                return 'I';

                        case (int) L'ó':
                        case (int) L'ö':
                                return 'o';

                        case (int) L'Ó':
                        case (int) L'Ö':
                                return 'O';

                        case (int) L'ú':
                        case (int) L'ü':
                                return 'u';

                        case (int) L'Ú':
                        case (int) L'Ü':
                                return 'U';

                        case (int) L'ñ':
                                return 'n';

                        case (int) L'Ñ':
                                return 'N';

                        default:
                                // Un caracter que no se que es
                                return '#';
                }
}


std::string Normalizador::normalizarLineaFrase(std::wstring linea){
	// Procesamos los caracteres uno a uno
	std::string s = "";
	for (unsigned i=0; i < linea.length(); ++i){

		// Se filtra el caracter y se lo agrega al final del string
		char c = filtrarCaracter(linea[i]);
		s.push_back(c);
	}

	return s;
}


// Cada linea es <apellido_autor>|<nombre_autor>|"<frase>"
BloqueFrase Normalizador::parsearLineaFrase(std::string linea){
	unsigned int divisor_A = linea.find('|');
	if (divisor_A == std::string::npos){
			throw std::runtime_error("La linea es invalida: " + linea);
	}

	unsigned int divisor_B = linea.find('|', divisor_A +1);
	if (divisor_B == std::string::npos){
			throw std::runtime_error("La linea es invalida: " + linea);
	}

	// Se separa la linea en sus componentes
	std::string apellido = linea.substr(0, divisor_A);
	std::string nombre = linea.substr(divisor_A +1, divisor_B - divisor_A -1);
	std::string frase = linea.substr(divisor_B +1);

	// Se eliminan las comillas en la frase
	if (frase[0] == '"' && frase[frase.length()-1] == '"') frase = frase.substr(1, frase.length()-2);

	// Se devuelve el bloque con la frase
	BloqueFrase bf;
	bf.setAutor( apellido + ", " +nombre);
	bf.setFrase(frase);

	return bf;
}


// Normaliza un caracter y elimina los signos
char Normalizador::normalizarCaracter(char c){
	int cint = (int) c;
	switch (cint){
		case (int) L'á':
		case (int) L'ä':
			return 'a';

		case (int) L'é':
		case (int) L'ë':
			return 'e';

		case (int) L'í':
		case (int) L'ï':
		case (int) L'î':
			return 'i';

		case (int) L'ó':
		case (int) L'ö':
			return 'o';

		case (int) L'ú':
		case (int) L'ü':
			return 'u';

		case (int) L'ñ':
			return 'n';

		default: // Algun simbolo o algo parecido
			return '\0';
	}
}


std::string Normalizador::toMinuscula(std::string palabra){
	std::string resul = palabra;

	// To lower case, robado de:
	// http://stackoverflow.com/questions/313970/stl-string-to-lower-case
	std::transform(palabra.begin(), palabra.end(), resul.begin(),
		std::bind2nd(std::ptr_fun(&std::tolower<char>), std::locale("es_AR.UTF8")));

	return resul;
}



// Toma una palabra con mayusculas y simbolos gramaticales y la normaliza
std::string Normalizador::normalizarPalabra(std::string palabra){
	if (palabra == "") return "";

	// A minuscula
	palabra = toMinuscula(palabra);

	// Procesamos los caracteres uno a uno
	int a = (int) 'a';
	int z = (int) 'z';
	std::string s = "";
	for (unsigned int i=0; i < palabra.length(); ++i){

		// Veo si es un simbolo o caracter raro
		char c = palabra[i];
		if (c < a || c > z){
			c = normalizarCaracter(c);
		}

		// Se lo agrega solo si es una letra
		if (c != '\0') s.push_back(c);
	}

	return s;
}


std::string Normalizador::normalizarFrase(std::string frase){
	std::string fraseNormal = "";
	std::stringstream ss(frase);
	do {
		std::string palabra = "";
		ss >> palabra;

		palabra = normalizarPalabra(palabra);
		fraseNormal += palabra + " ";

	} while (!ss.eof());

	return fraseNormal;
}


